import { ArcRotateCamera, BackgroundMaterial, Color3, Color4, CubeTexture, DirectionalLight, Engine, HemisphericLight, Mesh, MeshBuilder, Scene, ShadowGenerator, StandardMaterial, Texture, Texture, Vector3 } from "@babylonjs/core";

//环境纹理-反射
export default class SkyBox {

    public engine: Engine;
    public scene: Scene;
    public canvas: HTMLCanvasElement;

    private updateAction: Map<number, (time: number) => {}> = new Map();
    private updateActionId: number = 0;

    public static skyBox: SkyBox;

    public constructor(canvas: HTMLCanvasElement) {
        this.canvas = canvas;
        this.engine = new Engine(canvas, true);
        this.scene = this.createScene();

        this.init();

        SkyBox.skyBox = this;
    }

    private init() {
        this.update(0);
    }

    private createScene() {
        const { engine, canvas } = this;
        let scene = new Scene(engine);
        scene.clearColor = new Color4(0, 0, 0, 1);

        const camera = new ArcRotateCamera('Camera', -Math.PI / 2, Math.PI / 2.5, 10, new Vector3(0, 0, 0), scene);
        camera.attachControl(canvas, true);


        //半透反射(没感觉)
        // const texture = new Texture('https://assets.babylonjs.com/environments/backgroundGround.png');
        // texture.hasAlpha = true;//必须设置后才会显示为半透

        // const mat = new BackgroundMaterial('backMat');
        // mat.diffuseTexture = texture;
        // mat.opacityFresnel = false;//关闭菲尼尔反射?

        //天空盒反射
        const skyBox = MeshBuilder.CreateBox('skyBox', { size: 1000, sideOrientation: Mesh.BACKSIDE }, scene);
        const skyMat = new BackgroundMaterial('skyMat');
        skyMat.reflectionTexture = new CubeTexture('https://playground.babylonjs.com/textures/TropicalSunnyDay', scene);
        skyMat.reflectionTexture.coordinatesMode = Texture.SKYBOX_MODE;
        skyBox.material = skyMat;



        const dir = new DirectionalLight('dir', new Vector3(-1, -3, -1), scene)
        const sphere = MeshBuilder.CreateSphere('sphere');



        return scene;
    }

    private update(time: number) {
        const { updateAction, scene } = this;
        updateAction.forEach((action, key) => {
            action(time);
        });
        scene.render();
        requestAnimationFrame((time) => {
            this.update(time);
        });
    }

    public setUpdateAction(action: (time: number) => {}, id: number = -1) {
        const { updateAction } = this;
        let curId = id;
        if (id == -1) {
            curId = this.updateActionId++;
        } else if (id >= this.updateActionId) {
            curId = this.updateActionId++;
        }
        updateAction.set(curId, action);
    }
}